﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Hardware.Meter
{
    public class CommPort
    {

        public delegate void EventHandle(byte[] readBuffer);
        public event EventHandle DataReceived;

        public delegate void StatusEventHandle(string param);        
        public event StatusEventHandle StatusChanged;

        public SerialPort serialPort;
        Thread thread;

        private int sleepTime = 60;
        volatile bool _keepReading;

        public Settings.Port _setting;        

        public void PortSettings(Settings.Port settings)
        {
            _setting = settings;
        }

        public CommPort()
        {
            serialPort = new SerialPort();
            thread = null;
            _keepReading = false;
        }
        public CommPort(Settings.Port setting, int _sleepTime)
        {
            _setting = setting;
            serialPort = new SerialPort();
            thread = null;
            _keepReading = false;
            sleepTime = _sleepTime;
        }

        public bool IsOpen
        {
            get
            {
                return serialPort.IsOpen;
            }
        }

        private void StartReading()
        {
            if (!_keepReading)
            {
                _keepReading = true;
                thread = new Thread(new ThreadStart(ReadPort));
                thread.Start();
            }
        }

        private void StopReading()
        {
            if (_keepReading)
            {
                _keepReading = false;
                thread.Join();  
                thread = null;
            }
        }

        private void ReadPort()
        {
            while (_keepReading)
            {
                if (serialPort.IsOpen)
                {
                    int count = serialPort.BytesToRead;
                    if (count == 0) continue;
                    byte[] readBuffer = new byte[count];
                    try
                    {
                        Debug.Print($"串口接收到数据长度:{count}");
                        serialPort.Read(readBuffer, 0, count);
                        DataReceived?.Invoke(readBuffer);
                        Thread.Sleep(sleepTime);
                    }
                    catch (TimeoutException)
                    {
                    }
                }
                else
                {
                    TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
                    Thread.Sleep(waitTime);
                }               
            }
        }

        public void Open()
        {
            Close();
            try
            {
                serialPort.PortName = _setting.portName;
                serialPort.BaudRate = _setting.baudRate;
                serialPort.Parity = _setting.parity;
                serialPort.DataBits = _setting.dataBits;
                serialPort.StopBits = _setting.stopBits;
                serialPort.ReadTimeout = 100;
                serialPort.WriteTimeout = 100;
                serialPort.Open();
                StartReading();
            }
            catch (IOException)
            {
                StatusChanged(String.Format("{0}端口不存在！",_setting.portName));
            }
            catch (UnauthorizedAccessException)
            {
                StatusChanged(String.Format("{0} 端口已经使用！", _setting.portName));
            }
            catch (Exception ex)
            {
                StatusChanged(String.Format("{0}", ex.ToString()));
            }
            //更新状态
            if (serialPort.IsOpen)
            {
                StatusChanged(String.Format("{0}:{1}bps,数据位:{2},停止位:{3},校验:{4}", _setting.portName, _setting.baudRate, _setting.dataBits, (int)_setting.stopBits, _setting.parity.ToString().Substring(0, 1)));
            }
            else
            {
                StatusChanged(String.Format("{0} 端口已经使用！", _setting.portName));
            }
        }

        public void Close()
        {
            StopReading();
            serialPort.Close();
        }

        public void WritePort(byte[] send, int offSet, int count)
        {
            if (IsOpen)
            {
                serialPort.Write(send, offSet, count);
            }
        }

        public void WritePort(string data)
        {
            if (IsOpen)
            {
                serialPort.Write(data);
            }
        }

        public void Send(string data)
        {
            if (IsOpen)
            {
                serialPort.Write(data);
            }
        }

    }
}
